home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / base / netkit-b.07a / netkit-b / NetKit-B-0.07A / inetd / inetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-20  |  37.4 KB  |  1,661 lines

  1. /*
  2.  * Copyright (c) 1983,1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. char copyright[] =
  35.   "@(#) Copyright (c) 1983 Regents of the University of California.\n"
  36.   "All rights reserved.\n";
  37.  
  38. /*
  39.  * From: @(#)inetd.c    5.30 (Berkeley) 6/3/91
  40.  */
  41. char rcsid[] = 
  42.   "$Id: inetd.c,v 1.5 1996/07/20 20:46:09 dholland Exp $";
  43.  
  44.  
  45. /*
  46.  * Inetd - Internet super-server
  47.  *
  48.  * This program invokes all internet services as needed.
  49.  * connection-oriented services are invoked each time a
  50.  * connection is made, by creating a process.  This process
  51.  * is passed the connection as file descriptor 0 and is
  52.  * expected to do a getpeername to find out the source host
  53.  * and port.
  54.  *
  55.  * Datagram oriented services are invoked when a datagram
  56.  * arrives; a process is created and passed a pending message
  57.  * on file descriptor 0.  Datagram servers may either connect
  58.  * to their peer, freeing up the original socket for inetd
  59.  * to receive further messages on, or ``take over the socket'',
  60.  * processing all arriving datagrams and, eventually, timing
  61.  * out.     The first type of server is said to be ``multi-threaded'';
  62.  * the second type of server ``single-threaded''. 
  63.  *
  64.  * Inetd uses a configuration file which is read at startup
  65.  * and, possibly, at some later time in response to a hangup signal.
  66.  * The configuration file is ``free format'' with fields given in the
  67.  * order shown below.  Continuation lines for an entry must being with
  68.  * a space or tab.  All fields must be present in each entry.
  69.  *
  70.  *    service name            must be in /etc/services
  71.  *    socket type            stream/dgram/raw/rdm/seqpacket
  72.  *    protocol            must be in /etc/protocols
  73.  *    wait/nowait[.max]        single-threaded/multi-threaded, max #
  74.  *    user[.group]            user/group to run daemon as
  75.  *    server program            full path name
  76.  *    server program arguments    maximum of MAXARGS (20)
  77.  *
  78.  * For RPC services
  79.  *      service name/version            must be in /etc/rpc
  80.  *    socket type            stream/dgram/raw/rdm/seqpacket
  81.  *    protocol            must be in /etc/protocols
  82.  *    wait/nowait[.max]        single-threaded/multi-threaded
  83.  *    user[.group]            user to run daemon as
  84.  *    server program            full path name
  85.  *    server program arguments    maximum of MAXARGS (20)
  86.  *
  87.  * Comment lines are indicated by a `#' in column 1.
  88.  */
  89.  
  90. /*
  91.  * Here's the scoop concerning the user.group feature:
  92.  *
  93.  * 1) set-group-option off.
  94.  * 
  95.  *     a) user = root:    NO setuid() or setgid() is done
  96.  * 
  97.  *     b) other:    setuid()
  98.  *             setgid(primary group as found in passwd)
  99.  *             initgroups(name, primary group)
  100.  * 
  101.  * 2) set-group-option on.
  102.  * 
  103.  *     a) user = root:    NO setuid()
  104.  *             setgid(specified group)
  105.  *             NO initgroups()
  106.  * 
  107.  *     b) other:    setuid()
  108.  *             setgid(specified group)
  109.  *             initgroups(name, specified group)
  110.  * 
  111.  */
  112.  
  113. #include <sys/param.h>
  114. #include <sys/stat.h>
  115. #include <sys/ioctl.h>
  116. #include <sys/socket.h>
  117. #include <sys/un.h>
  118. #include <sys/file.h>
  119. #include <sys/wait.h>
  120. #include <sys/time.h>
  121. #include <sys/resource.h>
  122.  
  123. #ifndef __linux__
  124. #ifndef RLIMIT_NOFILE
  125. #define RLIMIT_NOFILE    RLIMIT_OFILE
  126. #endif
  127. #endif
  128.  
  129. #define RPC
  130.  
  131. #include <sys/param.h>
  132. #include <sys/stat.h>
  133. #include <sys/ioctl.h>
  134. #include <sys/socket.h>
  135. #include <sys/file.h>
  136. #include <sys/wait.h>
  137. #include <sys/time.h>
  138. #include <sys/resource.h>
  139.  
  140. #include <netinet/in.h>
  141. #include <arpa/inet.h>
  142.  
  143. #include <errno.h>
  144. #include <signal.h>
  145. #include <netdb.h>
  146. #include <syslog.h>
  147. #include <pwd.h>
  148. #include <grp.h>
  149. #include <stdio.h>
  150. #include <string.h>
  151. #ifdef RPC
  152. #include <rpc/rpc.h>
  153. #include <rpc/pmap_clnt.h>
  154. #endif
  155. #include "pathnames.h"
  156.  
  157. #ifndef MIN
  158. #define MIN(a, b)    ((a) < (b) ? (a) : (b))
  159. #endif
  160.  
  161. #define    TOOMANY        40        /* don't start more than TOOMANY */
  162. #define    CNT_INTVL    60        /* servers in CNT_INTVL sec. */
  163. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  164.  
  165. #define    SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  166.  
  167. int daemon(int, int);
  168.  
  169. void    config(), reapchild(), retry(), goaway();
  170. char    *index();
  171.  
  172. static int    debug = 0;
  173. static int    nsock, maxsock;
  174. static fd_set    allsock;
  175. static int    options;
  176. static int    timingout;
  177.  
  178. #ifdef MULOG
  179. static char    *curdom;
  180. #endif
  181.  
  182. #ifndef OPEN_MAX
  183. #define OPEN_MAX    64
  184. #endif
  185.  
  186. /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
  187. #define FD_MARGIN    (8)
  188. int    rlim_ofile_cur = OPEN_MAX;
  189.  
  190. #ifdef RLIMIT_NOFILE
  191. struct rlimit    rlim_ofile;
  192. #endif
  193.  
  194. struct    servtab {
  195.     char    *se_service;        /* name of service */
  196.     int    se_socktype;        /* type of socket to use */
  197.     int    se_family;        /* address family */
  198.     char    *se_proto;        /* protocol used */
  199.     int    se_rpcprog;        /* rpc program number */
  200.     int    se_rpcversl;        /* rpc program lowest version */
  201.     int    se_rpcversh;        /* rpc program highest version */
  202. #define isrpcservice(sep)    ((sep)->se_rpcversl != 0)
  203.     short    se_wait;        /* single threaded server */
  204.     short    se_checked;        /* looked at during merge */
  205.     char    *se_user;        /* user name to run as */
  206.     char    *se_group;        /* group name to run as */
  207.     struct    biltin *se_bi;        /* if built-in, description */
  208.     char    *se_server;        /* server program */
  209. #define    MAXARGV 20
  210.     char    *se_argv[MAXARGV+1];    /* program arguments */
  211.     int    se_fd;            /* open descriptor */
  212.     union {
  213.         struct    sockaddr se_un_ctrladdr;
  214.         struct    sockaddr_in se_un_ctrladdr_in;
  215.         struct    sockaddr_un se_un_ctrladdr_un;
  216.     } se_un;            /* bound address */
  217. #define se_ctrladdr    se_un.se_un_ctrladdr
  218. #define se_ctrladdr_in    se_un.se_un_ctrladdr_in
  219. #define se_ctrladdr_un    se_un.se_un_ctrladdr_un
  220.     int    se_ctrladdr_size;
  221.     int    se_max;            /* max # of instances of this service */
  222.     int    se_count;        /* number started since se_time */
  223.     struct    timeval se_time;    /* start of se_count */
  224. #ifdef MULOG
  225.     int    se_log;
  226. #define MULOG_RFC931    0x40000000
  227. #endif
  228.     struct    servtab *se_next;
  229. } *servtab;
  230.  
  231. static void echo_stream(int, struct servtab *);
  232. static void discard_stream(int, struct servtab *);
  233. static void machtime_stream(int, struct servtab *);
  234. static void daytime_stream(int, struct servtab *);
  235. static void chargen_stream(int, struct servtab *);
  236. static void echo_dg(int, struct servtab *);
  237. static void discard_dg(int, struct servtab *);
  238. static void machtime_dg(int, struct servtab *);
  239. static void daytime_dg(int, struct servtab *);
  240. static void chargen_dg(int, struct servtab *);
  241.  
  242. static void logpid(void);
  243. static int setconfig(void);
  244. static void endconfig(void);
  245. static void register_rpc(struct servtab *sep);
  246. static void unregister_rpc(struct servtab *sep);
  247. static void freeconfig(struct servtab *cp);
  248. static void print_service(const char *action, struct servtab *sep);
  249. static void setup(struct servtab *sep);
  250. static int bump_nofile(void);
  251.  
  252.  
  253. struct biltin {
  254.     char    *bi_service;        /* internally provided service name */
  255.     int    bi_socktype;        /* type of socket supported */
  256.     short    bi_fork;        /* 1 if should fork before call */
  257.     short    bi_wait;        /* 1 if should wait for child */
  258.     void    (*bi_fn)(int, struct servtab *); /* fn which performs it */
  259. } biltins[] = {
  260.     /* Echo received data */
  261.     { "echo",        SOCK_STREAM,    1, 0,    echo_stream, },
  262.     { "echo",        SOCK_DGRAM,    0, 0,    echo_dg, },
  263.  
  264.     /* Internet /dev/null */
  265.     { "discard",    SOCK_STREAM,    1, 0,    discard_stream, },
  266.     { "discard",    SOCK_DGRAM,    0, 0,    discard_dg, },
  267.  
  268.     /* Return 32 bit time since 1900 */
  269.     { "time",        SOCK_STREAM,    0, 0,    machtime_stream, },
  270.     { "time",        SOCK_DGRAM,    0, 0,    machtime_dg,     },
  271.  
  272.     /* Return human-readable time */
  273.     { "daytime",    SOCK_STREAM,    0, 0,    daytime_stream,     },
  274.     { "daytime",    SOCK_DGRAM,    0, 0,    daytime_dg,     },
  275.  
  276.     /* Familiar character generator */
  277.     { "chargen",    SOCK_STREAM,    1, 0,    chargen_stream,     },
  278.     { "chargen",    SOCK_DGRAM,    0, 0,    chargen_dg,     },
  279.  
  280.     { NULL, 0, 0, 0, NULL }
  281. };
  282.  
  283. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  284. char    *CONFIG = _PATH_INETDCONF;
  285. char    **Argv;
  286. char     *LastArg;
  287. char    *progname;
  288.  
  289. #ifdef sun
  290. /*
  291.  * Sun's RPC library caches the result of `dtablesize()'
  292.  * This is incompatible with our "bumping" of file descriptors "on demand"
  293.  */
  294. int
  295. _rpc_dtablesize()
  296. {
  297.     return rlim_ofile_cur;
  298. }
  299. #endif
  300.  
  301. int
  302. main(int argc, char *argv[], char *envp[])
  303. {
  304.     extern char *optarg;
  305.     extern int optind;
  306.     register struct servtab *sep;
  307.     register struct passwd *pwd;
  308.     register struct group *grp = NULL;
  309.     register int tmpint;
  310.     struct sigaction sa;
  311.     int ch, pid, dofork;
  312.     char buf[50];
  313.  
  314.     Argv = argv;
  315.     if (envp == 0 || *envp == 0)
  316.         envp = argv;
  317.     while (*envp)
  318.         envp++;
  319.     LastArg = envp[-1] + strlen(envp[-1]);
  320.  
  321.     progname = strrchr(argv[0], '/');
  322.     progname = progname ? progname + 1 : argv[0];
  323.  
  324.     while ((ch = getopt(argc, argv, "d")) != EOF)
  325.         switch(ch) {
  326.         case 'd':
  327.             debug = 1;
  328.             options |= SO_DEBUG;
  329.             break;
  330.         case '?':
  331.         default:
  332.             fprintf(stderr, "usage: %s [-d] [conf]", progname);
  333.             exit(1);
  334.         }
  335.     argc -= optind;
  336.     argv += optind;
  337.  
  338.     if (argc > 0)
  339.         CONFIG = argv[0];
  340.  
  341.     if (debug == 0)
  342.         daemon(0, 0);
  343.     openlog(progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  344.     logpid();
  345.  
  346. #ifdef RLIMIT_NOFILE
  347.     if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
  348.         syslog(LOG_ERR, "getrlimit: %m");
  349.     } else {
  350.         rlim_ofile_cur = rlim_ofile.rlim_cur;
  351.         if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
  352.             rlim_ofile_cur = OPEN_MAX;
  353.     }
  354. #endif
  355.  
  356.     config();
  357.     memset(&sa, 0, sizeof(sa));
  358.     sa.sa_mask = SIGBLOCK;
  359.     sa.sa_handler = retry;
  360.     sigaction(SIGALRM, &sa, NULL);
  361.     sa.sa_handler = config;
  362.     sigaction(SIGHUP, &sa, NULL);
  363.     sa.sa_handler = reapchild;
  364.     sigaction(SIGCHLD, &sa, NULL);
  365.     sa.sa_handler = goaway;
  366.     sigaction(SIGTERM, &sa, NULL);
  367.     sa.sa_handler = goaway;
  368.     sigaction(SIGINT, &sa,  NULL);
  369.  
  370.     {
  371.         /* space for daemons to overwrite environment for ps */
  372. #define    DUMMYSIZE    100
  373.         char dummy[DUMMYSIZE];
  374.  
  375.         (void)memset(dummy, 'x', DUMMYSIZE - 1);
  376.         dummy[DUMMYSIZE - 1] = '\0';
  377.  
  378.         (void)setenv("inetd_dummy", dummy, 1);
  379.     }
  380.  
  381.     for (;;) {
  382.         int n, ctrl;
  383.         fd_set readable;
  384.  
  385.         if (nsock == 0) {
  386.         (void) sigblock(SIGBLOCK);
  387.         while (nsock == 0)
  388.             sigpause(0L);
  389.         (void) sigsetmask(0L);
  390.         }
  391.         readable = allsock;
  392.         if ((n = select(maxsock + 1, &readable, (fd_set *)0,
  393.         (fd_set *)0, (struct timeval *)0)) <= 0) {
  394.             if (n < 0 && errno != EINTR)
  395.             syslog(LOG_WARNING, "select: %m\n");
  396.             sleep(1);
  397.             continue;
  398.         }
  399.         for (sep = servtab; n && sep; sep = sep->se_next)
  400.         if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  401.         n--;
  402.         if (debug)
  403.             fprintf(stderr, "someone wants %s\n", sep->se_service);
  404.         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
  405.             /* Fixed AGC */
  406.             fcntl(sep->se_fd,F_SETFL,O_NDELAY);
  407.             /* --------- */
  408.             ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  409.                 (int *)0);
  410.             fcntl(sep->se_fd,F_SETFL, 0);
  411.             if (debug)
  412.                 fprintf(stderr, "accept, ctrl %d\n", ctrl);
  413.             if (ctrl < 0) {
  414.                 if (errno == EINTR || errno == EWOULDBLOCK)
  415.                     continue;
  416.                 syslog(LOG_WARNING, "accept (for %s): %m",
  417.                     sep->se_service);
  418.                 continue;
  419.             }
  420.         } else
  421.             ctrl = sep->se_fd;
  422.         (void) sigblock(SIGBLOCK);
  423.         pid = 0;
  424.         dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  425.         if (dofork) {
  426.             if (sep->se_count++ == 0)
  427.                 (void)gettimeofday(&sep->se_time,
  428.                     (struct timezone *)0);
  429.             else if (sep->se_count >= sep->se_max) {
  430.                 struct timeval now;
  431.  
  432.                 (void)gettimeofday(&now, (struct timezone *)0);
  433.                 if (now.tv_sec - sep->se_time.tv_sec >
  434.                     CNT_INTVL) {
  435.                     sep->se_time = now;
  436.                     sep->se_count = 1;
  437.                 } else {
  438.                     syslog(LOG_ERR,
  439.             "%s/%s server failing (looping), service terminated\n",
  440.                         sep->se_service, sep->se_proto);
  441.                     FD_CLR(sep->se_fd, &allsock);
  442.                     (void) close(sep->se_fd);
  443.                     sep->se_fd = -1;
  444.                     sep->se_count = 0;
  445.                     nsock--;
  446.                     sigsetmask(0L);
  447.                     if (!timingout) {
  448.                         timingout = 1;
  449.                         alarm(RETRYTIME);
  450.                     }
  451.                     continue;
  452.                 }
  453.             }
  454.             pid = fork();
  455.         }
  456.         if (pid < 0) {
  457.             syslog(LOG_ERR, "fork: %m");
  458.             if (sep->se_socktype == SOCK_STREAM)
  459.                 close(ctrl);
  460.             sigsetmask(0L);
  461.             sleep(1);
  462.             continue;
  463.         }
  464.         if (pid && sep->se_wait) {
  465.             sep->se_wait = pid;
  466.             FD_CLR(sep->se_fd, &allsock);
  467.             nsock--;
  468.         }
  469.         sigsetmask(0L);
  470.         if (pid == 0) {
  471.             if (debug && dofork)
  472.                 setsid();
  473.             if (sep->se_bi)
  474.                 (*sep->se_bi->bi_fn)(ctrl, sep);
  475.             else {
  476.                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
  477.                     syslog(LOG_ERR,
  478.                         "getpwnam: %s: No such user",
  479.                         sep->se_user);
  480.                     if (sep->se_socktype != SOCK_STREAM)
  481.                         recv(0, buf, sizeof (buf), 0);
  482.                     _exit(1);
  483.                 }
  484.                 if (sep->se_group &&
  485.                     (grp = getgrnam(sep->se_group)) == NULL) {
  486.                     syslog(LOG_ERR,
  487.                         "getgrnam: %s: No such group",
  488.                         sep->se_group);
  489.                     if (sep->se_socktype != SOCK_STREAM)
  490.                         recv(0, buf, sizeof (buf), 0);
  491.                     _exit(1);
  492.                 }
  493.                 if (pwd->pw_uid) {
  494.                     if (sep->se_group)
  495.                         pwd->pw_gid = grp->gr_gid;
  496.                     (void) setgid((gid_t)pwd->pw_gid);
  497.                     initgroups(pwd->pw_name, pwd->pw_gid);
  498.                     (void) setuid((uid_t)pwd->pw_uid);
  499.                 } else if (sep->se_group) {
  500.                     (void) setgid((gid_t)grp->gr_gid);
  501.                 }
  502.                 if (debug)
  503.                     fprintf(stderr, "%d execl %s\n",
  504.                         getpid(), sep->se_server);
  505. #ifdef MULOG
  506.                 if (sep->se_log)
  507.                     dolog(sep, ctrl);
  508. #endif
  509.                 dup2(ctrl, 0);
  510.                 close(ctrl);
  511.                 dup2(0, 1);
  512.                 dup2(0, 2);
  513. #ifdef RLIMIT_NOFILE
  514.                 if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
  515.                     if (setrlimit(RLIMIT_NOFILE,
  516.                             &rlim_ofile) < 0)
  517.                         syslog(LOG_ERR,"setrlimit: %m");
  518.                 }
  519. #endif
  520.                 for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
  521.                     (void)close(tmpint);
  522.                 execv(sep->se_server, sep->se_argv);
  523.                 if (sep->se_socktype != SOCK_STREAM)
  524.                     recv(0, buf, sizeof (buf), 0);
  525.                 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
  526.                 _exit(1);
  527.             }
  528.         }
  529.         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  530.             close(ctrl);
  531.         }
  532.     }
  533. }
  534.  
  535. void
  536. reapchild()
  537. {
  538.     int status;
  539.     int pid;
  540.     register struct servtab *sep;
  541.  
  542.     for (;;) {
  543.         pid = wait3(&status, WNOHANG, (struct rusage *)0);
  544.         if (pid <= 0)
  545.             break;
  546.         if (debug)
  547.             fprintf(stderr, "%d reaped\n", pid);
  548.         for (sep = servtab; sep; sep = sep->se_next)
  549.             if (sep->se_wait == pid) {
  550.                 if (WIFEXITED(status) && WEXITSTATUS(status))
  551.                     syslog(LOG_WARNING,
  552.                         "%s: exit status 0x%x",
  553.                         sep->se_server, WEXITSTATUS(status));
  554.                 else if (WIFSIGNALED(status))
  555.                     syslog(LOG_WARNING,
  556.                         "%s: exit signal 0x%x",
  557.                         sep->se_server, WTERMSIG(status));
  558.                 sep->se_wait = 1;
  559.                 FD_SET(sep->se_fd, &allsock);
  560.                 nsock++;
  561.                 if (debug)
  562.                     fprintf(stderr, "restored %s, fd %d\n",
  563.                         sep->se_service, sep->se_fd);
  564.             }
  565.     }
  566. }
  567.  
  568. void
  569. config()
  570. {
  571.     register struct servtab *sep, *cp, **sepp;
  572.     struct servtab *getconfigent(), *enter();
  573.     long omask;
  574.     int n;
  575.  
  576.     if (!setconfig()) {
  577.         syslog(LOG_ERR, "%s: %m", CONFIG);
  578.         return;
  579.     }
  580.     for (sep = servtab; sep; sep = sep->se_next)
  581.         sep->se_checked = 0;
  582.     while ((cp = getconfigent())!=NULL) {
  583.         for (sep = servtab; sep; sep = sep->se_next)
  584.             if (strcmp(sep->se_service, cp->se_service) == 0 &&
  585.                 strcmp(sep->se_proto, cp->se_proto) == 0)
  586.                 break;
  587.         if (sep != 0) {
  588.             int i;
  589.  
  590. #define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
  591.  
  592.             omask = sigblock(SIGBLOCK);
  593.             /*
  594.              * sep->se_wait may be holding the pid of a daemon
  595.              * that we're waiting for.  If so, don't overwrite
  596.              * it unless the config file explicitly says don't 
  597.              * wait.
  598.              */
  599.             if (cp->se_bi == 0 && 
  600.                 (sep->se_wait == 1 || cp->se_wait == 0))
  601.                 sep->se_wait = cp->se_wait;
  602.             if (cp->se_max != sep->se_max)
  603.                 SWAP(int, cp->se_max, sep->se_max);
  604.             if (cp->se_user)
  605.                 SWAP(char *, sep->se_user, cp->se_user);
  606.             if (cp->se_group)
  607.                 SWAP(char *, sep->se_group, cp->se_group);
  608.             if (cp->se_server)
  609.                 SWAP(char *, sep->se_server, cp->se_server);
  610.             for (i = 0; i < MAXARGV; i++)
  611.                 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
  612. #undef SWAP
  613.             if (isrpcservice(sep))
  614.                 unregister_rpc(sep);
  615.             sep->se_rpcversl = cp->se_rpcversl;
  616.             sep->se_rpcversh = cp->se_rpcversh;
  617.             sigsetmask(omask);
  618.             freeconfig(cp);
  619.             if (debug)
  620.                 print_service("REDO", sep);
  621.         } else {
  622.             sep = enter(cp);
  623.             if (debug)
  624.                 print_service("ADD ", sep);
  625.         }
  626.         sep->se_checked = 1;
  627.  
  628.         switch (sep->se_family) {
  629.         case AF_UNIX:
  630.             if (sep->se_fd != -1)
  631.                 break;
  632.             (void)unlink(sep->se_service);
  633.             n = strlen(sep->se_service);
  634.             if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 
  635.                 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
  636.             strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
  637.             sep->se_ctrladdr_un.sun_family = AF_UNIX;
  638.             sep->se_ctrladdr_size = n +
  639.                     sizeof sep->se_ctrladdr_un.sun_family;
  640.             setup(sep);
  641.             break;
  642.         case AF_INET:
  643.             sep->se_ctrladdr_in.sin_family = AF_INET;
  644.             sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
  645.             if (isrpcservice(sep)) {
  646.                 struct rpcent *rp;
  647.  
  648.                 sep->se_rpcprog = atoi(sep->se_service);
  649.                 if (sep->se_rpcprog == 0) {
  650.                     rp = getrpcbyname(sep->se_service);
  651.                     if (rp == 0) {
  652.                         syslog(LOG_ERR,
  653.                             "%s: unknown service",
  654.                             sep->se_service);
  655.                         continue;
  656.                     }
  657.                     sep->se_rpcprog = rp->r_number;
  658.                 }
  659.                 if (sep->se_fd == -1)
  660.                     setup(sep);
  661.                 if (sep->se_fd != -1)
  662.                     register_rpc(sep);
  663.             } else {
  664.                 u_short port = htons(atoi(sep->se_service));
  665.  
  666.                 if (!port) {
  667.                     struct servent *sp;
  668.                     sp = getservbyname(sep->se_service,
  669.                                 sep->se_proto);
  670.                     if (sp == 0) {
  671.                         syslog(LOG_ERR,
  672.                             "%s/%s: unknown service",
  673.                             sep->se_service, sep->se_proto);
  674.                         continue;
  675.                     }
  676.                     port = sp->s_port;
  677.                 }
  678.                 if (port != sep->se_ctrladdr_in.sin_port) {
  679.                     sep->se_ctrladdr_in.sin_port = port;
  680.                     if (sep->se_fd != -1) {
  681.                         FD_CLR(sep->se_fd, &allsock);
  682.                         nsock--;
  683.                         (void) close(sep->se_fd);
  684.                     }
  685.                     sep->se_fd = -1;
  686.                 }
  687.                 if (sep->se_fd == -1)
  688.                     setup(sep);
  689.             }
  690.         }
  691.     }
  692.     endconfig();
  693.     /*
  694.      * Purge anything not looked at above.
  695.      */
  696.     omask = sigblock(SIGBLOCK);
  697.     sepp = &servtab;
  698.     while ((sep = *sepp) != NULL) {
  699.         if (sep->se_checked) {
  700.             sepp = &sep->se_next;
  701.             continue;
  702.         }
  703.         *sepp = sep->se_next;
  704.         if (sep->se_fd != -1) {
  705.             FD_CLR(sep->se_fd, &allsock);
  706.             nsock--;
  707.             (void) close(sep->se_fd);
  708.         }
  709.         if (isrpcservice(sep))
  710.             unregister_rpc(sep);
  711.         if (sep->se_family == AF_UNIX)
  712.             (void)unlink(sep->se_service);
  713.         if (debug)
  714.             print_service("FREE", sep);
  715.         freeconfig(sep);
  716.         free((char *)sep);
  717.     }
  718.     (void) sigsetmask(omask);
  719. }
  720.  
  721. void
  722. retry()
  723. {
  724.     register struct servtab *sep;
  725.  
  726.     timingout = 0;
  727.     for (sep = servtab; sep; sep = sep->se_next) {
  728.         if (sep->se_fd == -1) {
  729.             switch (sep->se_family) {
  730.             case AF_UNIX:
  731.             case AF_INET:
  732.                 setup(sep);
  733.                 if (sep->se_fd != -1 && isrpcservice(sep))
  734.                     register_rpc(sep);
  735.                 break;
  736.             }
  737.         }
  738.     }
  739. }
  740.  
  741. void
  742. goaway()
  743. {
  744.     register struct servtab *sep;
  745.  
  746.     for (sep = servtab; sep; sep = sep->se_next) {
  747.         if (sep->se_fd == -1)
  748.             continue;
  749.  
  750.         switch (sep->se_family) {
  751.         case AF_UNIX:
  752.             (void)unlink(sep->se_service);
  753.             break;
  754.         case AF_INET:
  755.             if (sep->se_wait == 1 && isrpcservice(sep))
  756.                 unregister_rpc(sep);
  757.             break;
  758.         }
  759.         (void)close(sep->se_fd);
  760.     }
  761.     (void)unlink(_PATH_INETDPID);
  762.     exit(0);
  763. }
  764.  
  765.  
  766. static void
  767. setup(struct servtab *sep)
  768. {
  769.     int on = 1;
  770.  
  771.     if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
  772.         syslog(LOG_ERR, "%s/%s: socket: %m",
  773.             sep->se_service, sep->se_proto);
  774.         return;
  775.     }
  776. #define    turnon(fd, opt) \
  777. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  778.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  779.         turnon(sep->se_fd, SO_DEBUG) < 0)
  780.         syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  781.     if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  782.         syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  783. #undef turnon
  784.     if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
  785.         syslog(LOG_ERR, "%s/%s: bind: %m",
  786.             sep->se_service, sep->se_proto);
  787.         (void) close(sep->se_fd);
  788.         sep->se_fd = -1;
  789.         if (!timingout) {
  790.             timingout = 1;
  791.             alarm(RETRYTIME);
  792.         }
  793.         return;
  794.     }
  795.     if (sep->se_socktype == SOCK_STREAM)
  796.         listen(sep->se_fd, 10);
  797.  
  798.     FD_SET(sep->se_fd, &allsock);
  799.     nsock++;
  800.     if (sep->se_fd > maxsock) {
  801.         maxsock = sep->se_fd;
  802.         if (maxsock > rlim_ofile_cur - FD_MARGIN)
  803.             bump_nofile();
  804.     }
  805. }
  806.  
  807. static void
  808. register_rpc(struct servtab *sep)
  809. {
  810. #ifdef RPC
  811.     int n;
  812.     struct sockaddr_in sin;
  813.     struct protoent *pp;
  814.  
  815.     if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
  816.         syslog(LOG_ERR, "%s: getproto: %m",
  817.             sep->se_proto);
  818.         return;
  819.     }
  820.     n = sizeof sin;
  821.     if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
  822.         syslog(LOG_ERR, "%s/%s: getsockname: %m",
  823.             sep->se_service, sep->se_proto);
  824.         return;
  825.     }
  826.  
  827.     for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  828.         if (debug)
  829.             fprintf(stderr, "pmap_set: %u %u %u %u\n",
  830.             sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
  831.         (void)pmap_unset(sep->se_rpcprog, n);
  832.         if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
  833.             syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
  834.             sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
  835.     }
  836. #endif /* RPC */
  837. }
  838.  
  839. static void
  840. unregister_rpc(struct servtab *sep)
  841. {
  842. #ifdef RPC
  843.     int n;
  844.  
  845.     for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  846.         if (debug)
  847.             fprintf(stderr, "pmap_unset(%u, %u)\n",
  848.                 sep->se_rpcprog, n);
  849.         if (!pmap_unset(sep->se_rpcprog, n))
  850.             syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
  851.                 sep->se_rpcprog, n);
  852.     }
  853. #endif /* RPC */
  854. }
  855.  
  856.  
  857. struct servtab *
  858. enter(cp)
  859.     struct servtab *cp;
  860. {
  861.     register struct servtab *sep;
  862.     long omask;
  863.  
  864.     sep = (struct servtab *)malloc(sizeof (*sep));
  865.     if (sep == (struct servtab *)0) {
  866.         syslog(LOG_ERR, "Out of memory.");
  867.         exit(-1);
  868.     }
  869.     *sep = *cp;
  870.     sep->se_fd = -1;
  871.     sep->se_rpcprog = -1;
  872.     omask = sigblock(SIGBLOCK);
  873.     sep->se_next = servtab;
  874.     servtab = sep;
  875.     sigsetmask(omask);
  876.     return (sep);
  877. }
  878.  
  879. FILE    *fconfig = NULL;
  880. struct    servtab serv;
  881. char    line[256];
  882. char    *skip(), *nextline();
  883.  
  884. static int
  885. setconfig()
  886. {
  887.  
  888.     if (fconfig != NULL) {
  889.         fseek(fconfig, 0L, L_SET);
  890.         return (1);
  891.     }
  892.     fconfig = fopen(CONFIG, "r");
  893.     return (fconfig != NULL);
  894. }
  895.  
  896. static void
  897. endconfig(void)
  898. {
  899.     if (fconfig) {
  900.         (void) fclose(fconfig);
  901.         fconfig = NULL;
  902.     }
  903. }
  904.  
  905. struct servtab *
  906. getconfigent()
  907. {
  908.     register struct servtab *sep = &serv;
  909.     int argc;
  910.     char *cp, *arg, *newstr();
  911.  
  912. more:
  913. #ifdef MULOG
  914.     while ((cp = nextline(fconfig)) && *cp == '#') {
  915.         /* Avoid use of `skip' if there is a danger of it looking
  916.          * at continuation lines.
  917.          */
  918.         do {
  919.             cp++;
  920.         } while (*cp == ' ' || *cp == '\t');
  921.         if (*cp == '\0')
  922.             continue;
  923.         if ((arg = skip(&cp)) == NULL)
  924.             continue;
  925.         if (strcmp(arg, "DOMAIN"))
  926.             continue;
  927.         if (curdom)
  928.             free(curdom);
  929.         curdom = NULL;
  930.         while (*cp == ' ' || *cp == '\t')
  931.             cp++;
  932.         if (*cp == '\0')
  933.             continue;
  934.         arg = cp;
  935.         while (*cp && *cp != ' ' && *cp != '\t')
  936.             cp++;
  937.         if (*cp != '\0')
  938.             *cp++ = '\0';
  939.         curdom = newstr(arg);
  940.     }
  941. #else
  942.     while ((cp = nextline(fconfig)) && *cp == '#')
  943.         ;
  944. #endif
  945.     if (cp == NULL)
  946.         return ((struct servtab *)0);
  947.     bzero((char *)sep, sizeof *sep);
  948.     sep->se_service = newstr(skip(&cp));
  949.     arg = skip(&cp);
  950.     if (arg == NULL)
  951.         goto more;
  952.  
  953.     if (strcmp(arg, "stream") == 0)
  954.         sep->se_socktype = SOCK_STREAM;
  955.     else if (strcmp(arg, "dgram") == 0)
  956.         sep->se_socktype = SOCK_DGRAM;
  957.     else if (strcmp(arg, "rdm") == 0)
  958.         sep->se_socktype = SOCK_RDM;
  959.     else if (strcmp(arg, "seqpacket") == 0)
  960.         sep->se_socktype = SOCK_SEQPACKET;
  961.     else if (strcmp(arg, "raw") == 0)
  962.         sep->se_socktype = SOCK_RAW;
  963.     else
  964.         sep->se_socktype = -1;
  965.  
  966.     sep->se_proto = newstr(skip(&cp));
  967.     if (strcmp(sep->se_proto, "unix") == 0) {
  968.         sep->se_family = AF_UNIX;
  969.     } else {
  970.         sep->se_family = AF_INET;
  971.         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
  972. #ifdef RPC
  973.             char *cp, *ccp;
  974.             cp = index(sep->se_service, '/');
  975.             if (cp == 0) {
  976.                 syslog(LOG_ERR, "%s: no rpc version",
  977.                     sep->se_service);
  978.                 goto more;
  979.             }
  980.             *cp++ = '\0';
  981.             sep->se_rpcversl =
  982.                 sep->se_rpcversh = strtol(cp, &ccp, 0);
  983.             if (ccp == cp) {
  984.         badafterall:
  985.                 syslog(LOG_ERR, "%s/%s: bad rpc version",
  986.                     sep->se_service, cp);
  987.                 goto more;
  988.             }
  989.             if (*ccp == '-') {
  990.                 cp = ccp + 1;
  991.                 sep->se_rpcversh = strtol(cp, &ccp, 0); 
  992.                 if (ccp == cp)
  993.                     goto badafterall;
  994.             }
  995. #else
  996.             syslog(LOG_ERR, "%s: rpc services not suported",
  997.                 sep->se_service);
  998.             goto more;
  999. #endif /* RPC */
  1000.         }
  1001.     }
  1002.     arg = skip(&cp);
  1003.     if (arg == NULL)
  1004.         goto more;
  1005.     {
  1006.         char    *s = index(arg, '.');
  1007.         if (s) {
  1008.             *s++ = '\0';
  1009.             sep->se_max = atoi(s);
  1010.         } else
  1011.             sep->se_max = TOOMANY;
  1012.     }
  1013.     sep->se_wait = strcmp(arg, "wait") == 0;
  1014.     sep->se_user = newstr(skip(&cp));
  1015.     sep->se_group = strchr(sep->se_user, '.');
  1016.     if (sep->se_group) {
  1017.         *sep->se_group++ = '\0';
  1018.     }
  1019.     sep->se_server = newstr(skip(&cp));
  1020.     if (strcmp(sep->se_server, "internal") == 0) {
  1021.         register struct biltin *bi;
  1022.  
  1023.         for (bi = biltins; bi->bi_service; bi++)
  1024.             if (bi->bi_socktype == sep->se_socktype &&
  1025.                 strcmp(bi->bi_service, sep->se_service) == 0)
  1026.                 break;
  1027.         if (bi->bi_service == 0) {
  1028.             syslog(LOG_ERR, "internal service %s unknown\n",
  1029.                 sep->se_service);
  1030.             goto more;
  1031.         }
  1032.         sep->se_bi = bi;
  1033.         sep->se_wait = bi->bi_wait;
  1034.     } else
  1035.         sep->se_bi = NULL;
  1036.     argc = 0;
  1037.     for (arg = skip(&cp); cp; arg = skip(&cp)) {
  1038. #if MULOG
  1039.         char *colon, *rindex();
  1040.  
  1041.         if (argc == 0 && (colon = rindex(arg, ':'))) {
  1042.             while (arg < colon) {
  1043.                 int    x;
  1044.                 char    *ccp;
  1045.  
  1046.                 switch (*arg++) {
  1047.                 case 'l':
  1048.                     x = 1;
  1049.                     if (isdigit(*arg)) {
  1050.                         x = strtol(arg, &ccp, 0);
  1051.                         if (ccp == arg)
  1052.                             break;
  1053.                         arg = ccp;
  1054.                     }
  1055.                     sep->se_log &= ~MULOG_RFC931;
  1056.                     sep->se_log |= x;
  1057.                     break;
  1058.                 case 'a':
  1059.                     sep->se_log |= MULOG_RFC931;
  1060.                     break;
  1061.                 default:
  1062.                     break;
  1063.                 }
  1064.             }
  1065.             arg = colon + 1;
  1066.         }
  1067. #endif
  1068.         if (argc < MAXARGV)
  1069.             sep->se_argv[argc++] = newstr(arg);
  1070.     }
  1071.     while (argc <= MAXARGV)
  1072.         sep->se_argv[argc++] = NULL;
  1073.     return (sep);
  1074. }
  1075.  
  1076. static void
  1077. freeconfig(struct servtab *cp)
  1078. {
  1079.     int i;
  1080.  
  1081.     if (cp->se_service)
  1082.         free(cp->se_service);
  1083.     if (cp->se_proto)
  1084.         free(cp->se_proto);
  1085.     if (cp->se_user)
  1086.         free(cp->se_user);
  1087.     /* Note: se_group is part of the newstr'ed se_user */
  1088.     if (cp->se_server)
  1089.         free(cp->se_server);
  1090.     for (i = 0; i < MAXARGV; i++)
  1091.         if (cp->se_argv[i])
  1092.             free(cp->se_argv[i]);
  1093. }
  1094.  
  1095. char *
  1096. skip(cpp)
  1097.     char **cpp;
  1098. {
  1099.     register char *cp = *cpp;
  1100.     char *start;
  1101.  
  1102.     if (*cpp == NULL)
  1103.         return ((char *)0);
  1104.  
  1105. again:
  1106.     while (*cp == ' ' || *cp == '\t')
  1107.         cp++;
  1108.     if (*cp == '\0') {
  1109.         int c;
  1110.  
  1111.         c = getc(fconfig);
  1112.         (void) ungetc(c, fconfig);
  1113.         if (c == ' ' || c == '\t')
  1114.             if ((cp = nextline(fconfig))!=NULL)
  1115.                 goto again;
  1116.         *cpp = (char *)0;
  1117.         return ((char *)0);
  1118.     }
  1119.     start = cp;
  1120.     while (*cp && *cp != ' ' && *cp != '\t')
  1121.         cp++;
  1122.     if (*cp != '\0')
  1123.         *cp++ = '\0';
  1124.     *cpp = cp;
  1125.     return (start);
  1126. }
  1127.  
  1128. char *
  1129. nextline(fd)
  1130.     FILE *fd;
  1131. {
  1132.     char *cp;
  1133.  
  1134.     if (fgets(line, sizeof (line), fd) == NULL)
  1135.         return ((char *)0);
  1136.     cp = index(line, '\n');
  1137.     if (cp)
  1138.         *cp = '\0';
  1139.     return (line);
  1140. }
  1141.  
  1142. char *
  1143. newstr(cp)
  1144.     char *cp;
  1145. {
  1146.     cp = strdup(cp ? cp : "");
  1147.     if (cp)    return(cp);
  1148.  
  1149.     syslog(LOG_ERR, "strdup: %m");
  1150.     exit(-1);
  1151. }
  1152.  
  1153. void
  1154. setproctitle(char *a, int s)
  1155. {
  1156.     int size;
  1157.     register char *cp;
  1158.     struct sockaddr_in sin;
  1159.     char buf[80];
  1160.  
  1161.     cp = Argv[0];
  1162.     size = sizeof(sin);
  1163.     if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
  1164.         (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  1165.     else
  1166.         (void) sprintf(buf, "-%s", a); 
  1167.     strncpy(cp, buf, LastArg - cp);
  1168.     cp += strlen(cp);
  1169.     while (cp < LastArg)
  1170.         *cp++ = ' ';
  1171. }
  1172.  
  1173. static void
  1174. logpid(void)
  1175. {
  1176.     FILE *fp;
  1177.  
  1178.     if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
  1179.         fprintf(fp, "%u\n", getpid());
  1180.         (void)fclose(fp);
  1181.     }
  1182. }
  1183.  
  1184. static int
  1185. bump_nofile(void)
  1186. {
  1187. #ifdef RLIMIT_NOFILE
  1188.  
  1189. #define FD_CHUNK    32
  1190.  
  1191.     struct rlimit rl;
  1192.  
  1193.     if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
  1194.         syslog(LOG_ERR, "getrlimit: %m");
  1195.         return -1;
  1196.     }
  1197.     rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
  1198.     if (rl.rlim_cur <= rlim_ofile_cur) {
  1199.         syslog(LOG_ERR,
  1200.             "bump_nofile: cannot extend file limit, max = %d",
  1201.             rl.rlim_cur);
  1202.         return -1;
  1203.     }
  1204.  
  1205.     if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
  1206.         syslog(LOG_ERR, "setrlimit: %m");
  1207.         return -1;
  1208.     }
  1209.  
  1210.     rlim_ofile_cur = rl.rlim_cur;
  1211.     return 0;
  1212.  
  1213. #else
  1214.     syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
  1215.     return -1;
  1216. #endif
  1217. }
  1218.  
  1219. /*
  1220.  * Internet services provided internally by inetd:
  1221.  */
  1222. #define    BUFSIZE    4096
  1223.  
  1224. /* Echo service -- echo data back */
  1225. /* ARGSUSED */
  1226. void
  1227. echo_stream(int s, struct servtab *sep)
  1228. {
  1229.     char buffer[BUFSIZE];
  1230.     int i;
  1231.  
  1232.     setproctitle(sep->se_service, s);
  1233.     while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
  1234.         write(s, buffer, i) > 0)
  1235.         ;
  1236.     exit(0);
  1237. }
  1238.  
  1239. /* ARGSUSED */
  1240. void
  1241. echo_dg(s, sep)            /* Echo service -- echo data back */
  1242.     int s;
  1243.     struct servtab *sep;
  1244. {
  1245.     char buffer[BUFSIZE];
  1246.     int i, size;
  1247.     struct sockaddr sa;
  1248.  
  1249.     size = sizeof(sa);
  1250.     if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  1251.         return;
  1252.     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  1253. }
  1254.  
  1255. /* Discard service -- ignore data */
  1256. /* ARGSUSED */
  1257. void
  1258. discard_stream(int s, struct servtab *sep)
  1259. {
  1260.     char buffer[BUFSIZE];
  1261.  
  1262.     setproctitle(sep->se_service, s);
  1263.     while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
  1264.             errno == EINTR)
  1265.         ;
  1266.     exit(0);
  1267. }
  1268.  
  1269. /* ARGSUSED */
  1270. void
  1271. discard_dg(s, sep)        /* Discard service -- ignore data */
  1272.     int s;
  1273.     struct servtab *sep;
  1274. {
  1275.     char buffer[BUFSIZE];
  1276.  
  1277.     (void) read(s, buffer, sizeof(buffer));
  1278. }
  1279.  
  1280. #include <ctype.h>
  1281. #define LINESIZ 72
  1282. char ring[128];
  1283. char *endring;
  1284.  
  1285. void
  1286. initring()
  1287. {
  1288.     register int i;
  1289.  
  1290.     endring = ring;
  1291.  
  1292.     for (i = 0; i <= 128; ++i)
  1293.         if (isprint(i))
  1294.             *endring++ = i;
  1295. }
  1296.  
  1297. /* Character generator */
  1298. /* ARGSUSED */
  1299. void
  1300. chargen_stream(int s, struct servtab *sep)
  1301. {
  1302.     register char *rs;
  1303.     int len;
  1304.     char text[LINESIZ+2];
  1305.  
  1306.     setproctitle(sep->se_service, s);
  1307.  
  1308.     if (!endring) {
  1309.         initring();
  1310.         rs = ring;
  1311.     }
  1312.  
  1313.     text[LINESIZ] = '\r';
  1314.     text[LINESIZ + 1] = '\n';
  1315.     for (rs = ring;;) {
  1316.         if ((len = endring - rs) >= LINESIZ)
  1317.             bcopy(rs, text, LINESIZ);
  1318.         else {
  1319.             bcopy(rs, text, len);
  1320.             bcopy(ring, text + len, LINESIZ - len);
  1321.         }
  1322.         if (++rs == endring)
  1323.             rs = ring;
  1324.         if (write(s, text, sizeof(text)) != sizeof(text))
  1325.             break;
  1326.     }
  1327.     exit(0);
  1328. }
  1329.  
  1330. /* ARGSUSED */
  1331. void
  1332. chargen_dg(s, sep)        /* Character generator */
  1333.     int s;
  1334.     struct servtab *sep;
  1335. {
  1336.     struct sockaddr sa;
  1337.     static char *rs;
  1338.     int len, size;
  1339.     char text[LINESIZ+2];
  1340.  
  1341.     if (endring == 0) {
  1342.         initring();
  1343.         rs = ring;
  1344.     }
  1345.  
  1346.     size = sizeof(sa);
  1347.     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
  1348.         return;
  1349.  
  1350.     if ((len = endring - rs) >= LINESIZ)
  1351.         bcopy(rs, text, LINESIZ);
  1352.     else {
  1353.         bcopy(rs, text, len);
  1354.         bcopy(ring, text + len, LINESIZ - len);
  1355.     }
  1356.     if (++rs == endring)
  1357.         rs = ring;
  1358.     text[LINESIZ] = '\r';
  1359.     text[LINESIZ + 1] = '\n';
  1360.     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  1361. }
  1362.  
  1363. /*
  1364.  * Return a machine readable date and time, in the form of the
  1365.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  1366.  * returns the number of seconds since midnight, Jan 1, 1970,
  1367.  * we must add 2208988800 seconds to this figure to make up for
  1368.  * some seventy years Bell Labs was asleep.
  1369.  */
  1370.  
  1371. long
  1372. machtime()
  1373. {
  1374.     struct timeval tv;
  1375.  
  1376.     if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  1377.         fprintf(stderr, "Unable to get time of day\n");
  1378.         return (0L);
  1379.     }
  1380.     return (htonl((long)tv.tv_sec + 2208988800UL));
  1381. }
  1382.  
  1383. /* ARGSUSED */
  1384. void
  1385. machtime_stream(s, sep)
  1386.     int s;
  1387.     struct servtab *sep;
  1388. {
  1389.     long result;
  1390.  
  1391.     result = machtime();
  1392.     (void) write(s, (char *) &result, sizeof(result));
  1393. }
  1394.  
  1395. /* ARGSUSED */
  1396. void
  1397. machtime_dg(s, sep)
  1398.     int s;
  1399.     struct servtab *sep;
  1400. {
  1401.     long result;
  1402.     struct sockaddr sa;
  1403.     int size;
  1404.  
  1405.     size = sizeof(sa);
  1406.     if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  1407.         return;
  1408.     result = machtime();
  1409.     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  1410. }
  1411.  
  1412. /* ARGSUSED */
  1413. void
  1414. daytime_stream(s, sep)        /* Return human-readable time of day */
  1415.     int s;
  1416.     struct servtab *sep;
  1417. {
  1418.     char buffer[256];
  1419.     time_t time(), clock;
  1420.     char *ctime();
  1421.  
  1422.     clock = time((time_t *) 0);
  1423.  
  1424.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1425.     (void) write(s, buffer, strlen(buffer));
  1426. }
  1427.  
  1428. /* ARGSUSED */
  1429. void
  1430. daytime_dg(s, sep)        /* Return human-readable time of day */
  1431.     int s;
  1432.     struct servtab *sep;
  1433. {
  1434.     char buffer[256];
  1435.     time_t time(), clock;
  1436.     struct sockaddr sa;
  1437.     int size;
  1438.     char *ctime();
  1439.  
  1440.     clock = time((time_t *) 0);
  1441.  
  1442.     size = sizeof(sa);
  1443.     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  1444.         return;
  1445.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1446.     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  1447. }
  1448.  
  1449. /*
  1450.  * print_service:
  1451.  *    Dump relevant information to stderr
  1452.  */
  1453. static void
  1454. print_service(const char *action, struct servtab *sep)
  1455. {
  1456.     if (isrpcservice(sep))
  1457.         fprintf(stderr,
  1458.             "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%x server=%s\n",
  1459.             action, sep->se_service,
  1460.             sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
  1461.             sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
  1462.             (int)sep->se_bi, sep->se_server);
  1463.     else
  1464.         fprintf(stderr,
  1465.             "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%x server=%s\n",
  1466.             action, sep->se_service, sep->se_proto,
  1467.             sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
  1468.             (int)sep->se_bi, sep->se_server);
  1469. }
  1470.  
  1471.  
  1472. #ifdef MULOG
  1473. dolog(sep, ctrl)
  1474.     struct servtab *sep;
  1475.     int        ctrl;
  1476. {
  1477.     struct sockaddr        sa;
  1478.     struct sockaddr_in    *sin = (struct sockaddr_in *)&sa;
  1479.     int            len = sizeof(sa);
  1480.     struct hostent        *hp;
  1481.     char            *host, *dp, buf[BUFSIZ], *rfc931_name();
  1482.     int            connected = 1;
  1483.  
  1484.     if (sep->se_family != AF_INET)
  1485.         return;
  1486.  
  1487.     if (getpeername(ctrl, &sa, &len) < 0) {
  1488.         if (errno != ENOTCONN) {
  1489.             syslog(LOG_ERR, "getpeername: %m");
  1490.             return;
  1491.         }
  1492.         if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
  1493.             syslog(LOG_ERR, "recvfrom: %m");
  1494.             return;
  1495.         }
  1496.         connected = 0;
  1497.     }
  1498.     if (sa.sa_family != AF_INET) {
  1499.         syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
  1500.         return;
  1501.     }
  1502.  
  1503.     hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
  1504.                 sizeof (sin->sin_addr.s_addr), AF_INET);
  1505.  
  1506.     host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
  1507.  
  1508.     switch (sep->se_log & ~MULOG_RFC931) {
  1509.     case 0:
  1510.         return;
  1511.     case 1:
  1512.         if (curdom == NULL || *curdom == '\0')
  1513.             break;
  1514.         dp = host + strlen(host) - strlen(curdom);
  1515.         if (dp < host)
  1516.             break;
  1517.         if (debug)
  1518.             fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
  1519.                     host, curdom);
  1520.         if (strcasecmp(dp, curdom) == 0)
  1521.             return;
  1522.         break;
  1523.     case 2:
  1524.     default:
  1525.         break;
  1526.     }
  1527.  
  1528.     openlog("", LOG_NOWAIT, MULOG);
  1529.  
  1530.     if (connected && (sep->se_log & MULOG_RFC931))
  1531.         syslog(LOG_INFO, "%s@%s wants %s",
  1532.                 rfc931_name(sin, ctrl), host, sep->se_service);
  1533.     else
  1534.         syslog(LOG_INFO, "%s wants %s",
  1535.                 host, sep->se_service);
  1536. }
  1537. /*
  1538.  * From tcp_log by
  1539.  *  Wietse Venema, Eindhoven University of Technology, The Netherlands.
  1540.  */
  1541. #if 0
  1542. static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
  1543. #endif
  1544.  
  1545. #include <setjmp.h>
  1546.  
  1547. #define    RFC931_PORT    113        /* Semi-well-known port */
  1548. #define    TIMEOUT        4
  1549. #define    TIMEOUT2    10
  1550.  
  1551. static sigjmp_buf timebuf;
  1552.  
  1553. /* timeout - handle timeouts */
  1554.  
  1555. static void timeout(sig)
  1556. int     sig;
  1557. {
  1558.     siglongjmp(timebuf, sig);
  1559. }
  1560.  
  1561. /* rfc931_name - return remote user name */
  1562.  
  1563. char *
  1564. rfc931_name(struct sockaddr_in *there, int ctrl)
  1565. {
  1566.     /* "there" is remote link information */
  1567.     struct sockaddr_in here;    /* local link information */
  1568.     struct sockaddr_in sin;        /* for talking to RFC931 daemon */
  1569.     int        length;
  1570.     int        s;
  1571.     unsigned    remote;
  1572.     unsigned    local;
  1573.     static char    user[256];        /* XXX */
  1574.     char        buf[256];
  1575.     char        *cp;
  1576.     char        *result = "USER_UNKNOWN";
  1577.     int        len;
  1578.  
  1579.     /* Find out local port number of our stdin. */
  1580.  
  1581.     length = sizeof(here);
  1582.     if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
  1583.         syslog(LOG_ERR, "getsockname: %m");
  1584.         return (result);
  1585.     }
  1586.     /* Set up timer so we won't get stuck. */
  1587.  
  1588.     if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  1589.         syslog(LOG_ERR, "socket: %m");
  1590.         return (result);
  1591.     }
  1592.  
  1593.     sin = here;
  1594.     sin.sin_port = htons(0);
  1595.     if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
  1596.         syslog(LOG_ERR, "bind: %m");
  1597.         return (result);
  1598.     }
  1599.  
  1600.     signal(SIGALRM, timeout);
  1601.     if (sigsetjmp(timebuf)) {
  1602.         close(s);            /* not: fclose(fp) */
  1603.         return (result);
  1604.     }
  1605.     alarm(TIMEOUT);
  1606.  
  1607.     /* Connect to the RFC931 daemon. */
  1608.  
  1609.     sin = *there;
  1610.     sin.sin_port = htons(RFC931_PORT);
  1611.     if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
  1612.         close(s);
  1613.         alarm(0);
  1614.         return (result);
  1615.     }
  1616.  
  1617.     /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
  1618.     sprintf(buf, "%u,%u\r\n", ntohs(there->sin_port), ntohs(here.sin_port));
  1619.  
  1620.  
  1621.     for (len = 0, cp = buf; len < strlen(buf); ) {
  1622.         int    n;
  1623.         if ((n = write(s, cp, strlen(buf) - len)) == -1) {
  1624.             close(s);
  1625.             alarm(0);
  1626.             return (result);
  1627.         }
  1628.         cp += n;
  1629.         len += n;
  1630.     }
  1631.  
  1632.     /* Read response */
  1633.     for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
  1634.         char    c;
  1635.         if (read(s, &c, 1) != 1) {
  1636.             close(s);
  1637.             alarm(0);
  1638.             return (result);
  1639.         }
  1640.         if (c == '\n')
  1641.             break;
  1642.         *cp++ = c;
  1643.     }
  1644.     *cp = '\0';
  1645.  
  1646.     if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
  1647.         && ntohs(there->sin_port) == remote
  1648.         && ntohs(here.sin_port) == local) {
  1649.  
  1650.         /* Strip trailing carriage return. */
  1651.         if (cp = strchr(user, '\r'))
  1652.             *cp = 0;
  1653.         result = user;
  1654.     }
  1655.  
  1656.     alarm(0);
  1657.     close(s);
  1658.     return (result);
  1659. }
  1660. #endif
  1661.